<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2023-01-31 16:47:12
 * @Last Modified time: 2023-02-13 16:51:01
 */

namespace app\common\services\store;

use frank\base\BaseService;
use frank\exception\CommonException;
use frank\utils\helper\ArrayHelper;
use app\common\services\store\GoodsService;
use app\common\services\store\GoodsSkuService;

use frank\services\CacheService;

/**
 * 购物车
 * Class CartService
 * 缓存 redis
 */
class CartService extends BaseService
{
    /* @var 用户 */
    private $user;

    /* @var int $uid 用户id */
    private $uid;

    /* @var array $cart 购物车列表 */
    private $cart = [];

    private $cacheKey = "store:cart:";

    /* @var bool $clear 是否清空购物车 */
    private $clear = false;

    public function __construct(CacheService $dao)
    {
		$this->dao = $dao::instance();
    }

    /**
     * 析构方法
     * 将cart数据保存到缓存文件
     */
    public function __destruct()
    {
        if( $this->clear !== true && $this->uid ){
            $this->dao->setTokenBucket($this->cacheKey.$this->uid, $this->cart, 86400 * 60);
        }
    }

    /**
     * 
     */
    public function init($user){
        $this->user = $user;
        $this->uid = $user['id'] ?? 0;
        $this->cart = $this->dao->getTokenBucket($this->cacheKey. $this->uid) ?: [];
        return $this;
    }

     /**
     * 加入购物车
     */
    public function create($goodsId, $goodsNum, $goodsSkuId)
    {
         // 获取商品信息
        $goods = GoodsService::instance()->detail($goodsId);
        // 购物车商品索引
        $indexs = "{$goodsId}_{$goodsSkuId}";
        // 加入购物车后的商品数量
        $cartGoodsNum = $goodsNum + (isset($this->cart[$indexs]) ? $this->cart[$indexs]['goods_num'] : 0);
        // 验证商品能否加入
        if (!$this->checkGoods($goods, $goodsSkuId, $cartGoodsNum)) {
            return false;
        }
        // 记录到购物车列表
        $this->cart[$indexs] = [
            'goods_id' => $goodsId,
            'goods_num' => $cartGoodsNum,
            'goods_sku_id' => $goodsSkuId,
            'create_time' => time()
        ];
        return true;
    }

    /**
     * 修改购物车中某商品数量
     */
    public function update($goodsId,$goodsNum, $goodsSkuId)
    {
        $index = "{$goodsId}_{$goodsSkuId}";
        if(!empty($this->cart) && !empty($this->cart[$index])){
            $this->cart[$index]['goods_num'] = $goodsNum;
        }
    }

    /**
     * 购物车列表 (含商品信息)
     */
    public function getList($cartIds)
    {
        // 获取购物车商品列表
        return $this->getOrderGoodsList($cartIds);
    }

    /**
     * 获取购物车中的商品列表
     */
    private function getOrderGoodsList($cartIds)
    {
        // 购物车商品列表
        $goodsList = [];
        // 获取购物车列表
        $cartList = $this->getCartList($cartIds);
        $createTime = array_column($cartList,'create_time');
        array_multisort($createTime,SORT_DESC,$cartList);
        if (empty($cartList)) {
            $this->setError('当前购物车没有商品');
            return $goodsList;
        }
        // 购物车中所有商品id集
        $goodsIds = array_unique(ArrayHelper::getArrayColumn($cartList, 'goods_id'));

        $goodsService = GoodsService::instance();
        // 获取并格式化商品数据
        $sourceData = $goodsService->search(['id'=>$goodsIds])->with(['sku'])->hidden(['content'])->select();
        $sourceData = ArrayHelper::arrayColumn2Key($sourceData, 'id');
        foreach ($cartList as $key => $item) {
            // 格式化购物车数据列表
            // 判断商品不存在则自动删除
            if (!isset($sourceData[$item['goods_id']])) {
                $this->delete($key);
                continue;
            }
            /* @var GoodsM $goods 商品信息 */
            $goods = clone $sourceData[$item['goods_id']];
            $goods['goods_sku_id'] = $item['goods_sku_id'];
            $goods['goods_num'] = $item['goods_num'];
            $goods = $goodsService->checkOrderGoods([$goods]);
            if (!$goods && !$goodsService->hasError()) {
                $this->delete($key);
                continue;
            }
            $goodsList[] = $goods[0];
        }

        return $goodsList;
    }

    /**
     * 获取购物车列表
     * @param string|null $cartIds 购物车索引集 (为null时则获取全部)
     * @return array
     */
    public function getCartList($cartIds = null)
    {
        if (empty($cartIds)) return $this->cart;
        $cartList = [];
        $indexArr = (strpos($cartIds, ',') !== false) ? explode(',', $cartIds) : [$cartIds];
        foreach ($indexArr as $index) {
            if(!empty($this->cart) && !empty($this->cart)){
                foreach ($this->cart as $key => $value) {
                    if($key == $index){
                        $cartList[$index] = $value;
                    }
                }
            }
        }
        return $cartList;
    }


    /**
     * 获取当前用户购物车商品总数量
     */
    public function getGoodsNums()
    {
        $countArr = [];
        foreach ($this->cart as $key => $value) {
            $countArr[] = $value['goods_num'];
        }
        return array_sum($countArr);
    }

    /**
     * 获取当前用户购物车商品数量
     */
    public function getGoodsNum($goodsId)
    {
        $count = 0;
        foreach ($this->cart as $key => $item) {
            if($item['goods_id'] == $goodsId){
                $count += $item['goods_num'];
            }
        }
        return $count;
    }

     /**
     * 验证商品是否可以购买
     */
    private function checkGoods($goods, $goodsSkuId, $cartGoodsNum)
    {
        // 判断商品是否下架
        if (!$goods || $goods['delete_time'] || !$goods['goods_status']['value']) {
            $this->setError('很抱歉，商品信息不存在或已下架');
            return false;
        }
        // 商品sku信息
        $goods['goods_sku'] = GoodsService::instance()->getGoodsSkuItem($goods, $goodsSkuId);
        // 判断商品库存
        if ($cartGoodsNum > $goods['goods_sku']['stock']) {
            $this->setError('很抱歉，商品库存不足');
            return false;
        }
        return true;
    }

    /**
     * 清空当前用户购物车
     */
    public function clearAll($cartIds = null)
    {
        if (empty($cartIds)) {
            $this->clear = true;
            $this->dao->clearToken('cart_' . $this->uid);
        } else {
            $this->delete($cartIds);
        }
    }


    /**
     * 删除购物车中指定商品
     */
    public function delete($cartIds)
    {

        if(!is_array($cartIds)){
            $cartIds = strpos($cartIds, ',') !== false ? explode(',', $cartIds) : [$cartIds];
        }
        foreach ($cartIds as $indexs) {
            if (isset($this->cart[$indexs])) unset($this->cart[$indexs]);
            if(empty($this->cart[$indexs])) unset($this->cart[$indexs]);
        }
    }
}
